package com.zzb.framework.role.service;

import com.alibaba.fastjson.JSON;

import com.zzb.framework.common.BaseResponse;
import com.zzb.framework.common.BaseService;
import com.zzb.framework.common.ServiceException;
import com.zzb.framework.role.dao.SysMenuDAO;
import com.zzb.framework.role.entity.IUser;
import com.zzb.framework.role.entity.SysMenu;
import com.zzb.framework.role.vo.SysMenuTreeVO;
import com.zzb.framework.role.vo.SysRoleMenuTreeVO;
import com.zzb.framework.validator.annotation.ValidatorEnabled;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 菜单表 service类
 */
@Service
public class SysMenuService extends BaseService<SysMenuDAO, SysMenu> {
    private static final Logger logger = LoggerFactory.getLogger(SysMenuService.class);
    @Autowired
    private SysMenuDAO sysMenuDAO;

    @Override
    public SysMenuDAO getDAO() {
        return sysMenuDAO;
    }

    /**
     * 删除菜单表
     */
    public BaseResponse deleteMenu(String id, IUser operate) throws ServiceException {
        //TODO  ZZB 20170222
        return deleteById(id);
    }

    /**
     * 保存菜单表
     */
    @ValidatorEnabled
    public BaseResponse<SysMenu> saveMenu(SysMenu sysMenu, IUser operator) throws ServiceException {
        logger.info("正在保存菜单表[" + JSON.toJSONString(sysMenu) + "][" + JSON.toJSONString(operator) + "]");
        //TODO  ZZB 20170222
        return insertOrUpdate(sysMenu, operator);
    }

    /**获取角色菜单树形VO*/
    public SysRoleMenuTreeVO getRoleMenuTreeVOByRoleId(String roleId){
        List<SysMenu> selectedSysMenu = getDAO().listByRoleId(roleId);
        return getRoleMenuTreeVOByList( getDAO().listOrderByMenuLevelAscMenuOrderAsc(), selectedSysMenu);
    }

    /**
     * 对treeVo做先序便利输出成列表，并在name前加制表符*/
    public List<SysMenu> preOrderTreeVo(SysMenuTreeVO sysMenuTreeVO){
        List<SysMenu> list = new ArrayList<>();
        String tableSymbol = "";
        if(sysMenuTreeVO !=null && CollectionUtils.isNotEmpty(sysMenuTreeVO.getSubs())){
            for (SysMenuTreeVO treeVo : sysMenuTreeVO.getSubs()) {
                preOrderTreeVoProcessor(treeVo,list,tableSymbol);
            }
        }
        if(CollectionUtils.isNotEmpty(list)){
            SysMenu sysMenu = list.get(list.size() - 1);
            sysMenu.setMenuName(sysMenu.getMenuName().replaceAll("├","└"));
        }
        return list;
    }
    /**
     * 对treeVo做先序便利输出成列表的递归方法体
     * */
    private void preOrderTreeVoProcessor(final SysMenuTreeVO sysMenuTreeVO, final List<SysMenu> list , String tableSymbol){
        SysMenu sysMenu = sysMenuTreeVO.getSysMenu();
        sysMenu.setMenuName(tableSymbol + sysMenu.getMenuName());
        list.add(sysMenu);
        tableSymbol = tableSymbol + "├─";
        if(CollectionUtils.isNotEmpty(sysMenuTreeVO.getSubs())){
            for (SysMenuTreeVO treeVo : sysMenuTreeVO.getSubs()) {
                preOrderTreeVoProcessor(treeVo,list,tableSymbol);
            }
        }
    }

    /**
     * 获取用户菜单
     * 构建菜单树
     */
    public SysMenuTreeVO getTreeVoByUserId(String userId){
        List<SysMenu> sysMenuList = getDAO().listByUserId(userId);
        return getTreeVOByList(sysMenuList);
    }
    /**
     * 获取角色菜单
     * 构建菜单树
     */
    public SysMenuTreeVO getTreeVOByRoleId(String roleId){
        return getTreeVOByList(getDAO().listByRoleId(roleId));
    }
    /**
     * 获取所有菜单
     * 构建菜单树
     */
    public SysMenuTreeVO getTreeVO(){
        List<SysMenu> sysMenuList = getDAO().listOrderByMenuLevelAscMenuOrderAsc();
        return getTreeVOByList(sysMenuList);
    }
    /**
     * 构建菜单树
     * 使用LinkedHashMap做排序，时间复杂度在O(n)
     */
    private SysMenuTreeVO getTreeVOByList(List<SysMenu> sysMenuList ) {

        SysMenuTreeVO sysMenuTreeVO = buildRootTreeVO();
        LinkedHashMap<String, List<SysMenuTreeVO>> parentKeyMap = sysMenuList.stream()
            .collect(LinkedHashMap::new,
                (linkedHashMap, sysMenu) -> {
                    String parentId;
                    parentId = StringUtils.isEmpty(sysMenu.getMenuParentId()) ? "root" : sysMenu.getMenuParentId();
                    List<SysMenuTreeVO> list;
                    if (!linkedHashMap.containsKey(parentId)) {
                        list = new ArrayList<>();
                        linkedHashMap.put(parentId, list);
                    } else {
                        list = linkedHashMap.get(parentId);
                    }
                    SysMenuTreeVO vo = new SysMenuTreeVO();
                    vo.setSubs(new ArrayList<>());
                    vo.setSysMenu(sysMenu);
                    vo.setRoot(false);
                    vo.setLevel(sysMenu.getMenuLevel());
                    list.add(vo);
                },
                (map, map2) -> map2.forEach((key, value) -> {
                    map.computeIfAbsent(key, s -> value);
                    map.computeIfPresent(key, (s, valueList) -> {
                        valueList.addAll(value);
                        return valueList.stream()
                                .sorted((o1, o2) -> o1.getSysMenu().getMenuOrder() > o2.getSysMenu().getMenuOrder() ? -1 : 1)
                                .collect(Collectors.toList());
                    });
                })
            );
        List<SysMenuTreeVO> vosList = parentKeyMap.values().stream()
            .collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);

        vosList.forEach(vo -> {
            if (parentKeyMap.containsKey(vo.getSysMenu().getId())) {
                vo.setSubs(parentKeyMap.get(vo.getSysMenu().getId()));
            }
            if (vo.getLevel() == 1) {
                sysMenuTreeVO.getSubs().add(vo);
            }
        });
        return sysMenuTreeVO;
    }

    /**
     * 构建菜单树形视图的根对象
     */
    private SysMenuTreeVO buildRootTreeVO() {
        SysMenuTreeVO sysMenuTreeVO = new SysMenuTreeVO();
        sysMenuTreeVO.setLevel(0);
        sysMenuTreeVO.setRoot(true);
        sysMenuTreeVO.setSubs(new ArrayList<>());
        return sysMenuTreeVO;
    }

    /**
     * 构建权限菜单树
     * 使用LinkedHashMap做排序，时间复杂度在O(n)
     */
    private SysRoleMenuTreeVO getRoleMenuTreeVOByList(List<SysMenu> sysMenuList,List<SysMenu> selectedSysMenuList ) {
        final Map<String , SysMenu> selectedSysMenuMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(selectedSysMenuList)){
            selectedSysMenuMap.putAll(selectedSysMenuList.stream().collect(HashMap::new,(hashMap, sysMenu) -> hashMap.put(sysMenu.getId(),sysMenu), HashMap::putAll));
        }
        SysRoleMenuTreeVO sysRoleMenuTreeVO = buildRootRoleMenuTreeVO();
        LinkedHashMap<String, List<SysRoleMenuTreeVO>> parentKeyMap = sysMenuList.stream()
                .collect(LinkedHashMap::new,
                        (linkedHashMap, sysMenu) -> {
                            String parentId;
                            parentId = StringUtils.isEmpty(sysMenu.getMenuParentId()) ? "root" : sysMenu.getMenuParentId();
                            List<SysRoleMenuTreeVO> list;
                            if (!linkedHashMap.containsKey(parentId)) {
                                list = new ArrayList<>();
                                linkedHashMap.put(parentId, list);
                            } else {
                                list = linkedHashMap.get(parentId);
                            }
                            SysRoleMenuTreeVO vo = new SysRoleMenuTreeVO();
                            vo.setSubs(new ArrayList<>());
                            vo.setSysMenu(sysMenu);
                            vo.setRoot(false);
                            vo.setSelected(selectedSysMenuMap.containsKey(sysMenu.getId()));
                            vo.setLevel(sysMenu.getMenuLevel());
                            list.add(vo);
                        },
                        (map, map2) -> map2.forEach((key, value) -> {
                            map.computeIfAbsent(key, s -> value);
                            map.computeIfPresent(key, (s, valueList) -> {
                                valueList.addAll(value);
                                return valueList.stream()
                                        .sorted((o1, o2) -> o1.getSysMenu().getMenuOrder() > o2.getSysMenu().getMenuOrder() ? -1 : 1)
                                        .collect(Collectors.toList());
                            });
                        })
                );
        List<SysRoleMenuTreeVO> vosList = parentKeyMap.values().stream()
                .collect(ArrayList::new, ArrayList::addAll, ArrayList::addAll);

        vosList.forEach(vo -> {
            if (parentKeyMap.containsKey(vo.getSysMenu().getId())) {
                vo.setSubs(parentKeyMap.get(vo.getSysMenu().getId()));
            }
            if (vo.getLevel() == 1) {
                sysRoleMenuTreeVO.getSubs().add(vo);
            }
        });
        return sysRoleMenuTreeVO;
    }
    /**
     * 构建权限菜单树形视图的根对象
     */
    private SysRoleMenuTreeVO buildRootRoleMenuTreeVO() {
        SysRoleMenuTreeVO sysRoleMenuTreeVO = new SysRoleMenuTreeVO();
        sysRoleMenuTreeVO.setLevel(0);
        sysRoleMenuTreeVO.setRoot(true);
        sysRoleMenuTreeVO.setSubs(new ArrayList<>());
        sysRoleMenuTreeVO.setSelected(false);
        return sysRoleMenuTreeVO;
    }

}
